<?php
require_once "./core/functions.php";
require_dir ( dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . "controllers" . DIRECTORY_SEPARATOR );
class FrontController {
	
	protected $_controller, $_action, $_params, $_body, $_baseurl;
	protected $_file_redir = array ("js" => "js", "css" => "style", "jpg" => "images", "gif" => "images", "png" => "images", "bmp" => "images", "jpeg" => "images" );
	protected $_file, $_key;
	static $_instance;
	
	public static function getInstance() {
		if (! (self::$_instance instanceof self)) {
			self::$_instance = new self ();
		}
		return self::$_instance;
	}
	
	private function __construct() {
		$request = $_SERVER ['PHP_SELF'];
		$baseurl = substr ( $request, 0, strpos ( $request, basename ( $_SERVER ['SCRIPT_NAME'] ) ) + strlen ( basename ( $_SERVER ['SCRIPT_NAME'] ) ) );
		$this->_baseurl = substr ( $baseurl, 0, strlen ( $baseurl ) - 9 );
		$request = substr ( $request, strpos ( $request, basename ( $_SERVER ['SCRIPT_NAME'] ) ) + strlen ( basename ( $_SERVER ['SCRIPT_NAME'] ) ) );
		$splits = explode ( '/', trim ( $request, '/' ) );
		$len = count ( $splits );
		$file = $splits [$len - 1];
		$type = explode ( ".", trim ( $file, "." ) );
		if (isset ( $type [1] ) && array_key_exists ( $type [1], $this->_file_redir )) {
			$this->_file = $file;
			$this->_key = $type [1];
		} else {
			$this->_controller = ! empty ( $splits [0] ) ? $splits [0] . 'Controller' : 'PageController';
			$this->_action = ! empty ( $splits [1] ) ? $splits [1] : 'index';
			if (! empty ( $splits [2] )) {
				$keys = $values = array ();
				for($i = 2, $count = count ( $splits ); $i < $count; $i ++) {
					if ($i % 2 == 0) {
						// & values
						$keys [] = $splits [$i];
					} else {
						// & key
						$values [] = $splits [$i];
					}
				}
				$this->_params = array_combine ( $keys, $values );
				$_GET = array_merge ( $_GET, $this->_params );
			}
			$_GET ['controller'] = basename ( $this->_controller, 'Controller' );
			$_GET ['action'] = $this->_action;
		}
	
	}
	
	public function route() {
		if (isset ( $this->_file )) {
			$this->redir ();
		}
		if (class_exists ( $this->getController () )) {
			$rc = new ReflectionClass ( $this->getController () );
			if ($rc->implementsInterface ( 'IController' )) {
				if ($rc->hasMethod ( $this->getAction () . 'Action' )) {
					$controller = $rc->newInstance ();
					$method = $rc->getMethod ( $this->getAction () . 'Action' );
					if (! $this->accessRuleCheck ( $controller, $method )) {
						$method = $rc->getMethod ( 'forbidAction' );
						$method->invoke ( $controller );
						return;
					}
				} else {
					//throw new Exception("Action");
					$this->to404 ();
				}
			} else {
				//throw new Exception("Interface");
				$this->to404 ();
			}
		} else {
			//throw new Exception("Controller");
			$this->to404 ();
		}
	
	}
	
	public function redir() {
		$key = $this->_key;
		$file = $this->_file;
		$dir = $this->_file_redir [$key];
		;
		Header ( "HTTP/1.1 303 See Other" );
		Header ( "Location:" . "http://" . $_SERVER ['HTTP_HOST'] . $this->_baseurl . $dir . "/" . $file );
	}
	public function getParams() {
		return $this->_params;
	}
	
	public function getController() {
		return $this->_controller;
	}
	
	public function getAction() {
		return $this->_action;
	}
	private function accessRuleCheck($controller, $method) {
		if (! isset ( $_SESSION ['userinfo'] ))
			return false;
		$userinfo= $_SESSION['userinfo'];
		$rule = $controller->getAccessRule();
		$role = $userinfo['type'];
		if($role==UserBean::$_ADMIN){
			$method->invoke ( $controller );
			return true;
		}
		$permit = array();
		if(isset($rule[$role]))
			$permit+=$rule[$role];
		$permit=array_merge($permit,$rule['*']);
		if(!in_array($this->getAction(),$permit))
			return false;
		$method->invoke ( $controller );
		return true;
	}
	private function to404() {
		$rc = new ReflectionClass ( 'pageController' );
		$controller = $rc->newInstance ();
		$method = $rc->getMethod ( 'to404Action' );
		$method->invoke ( $controller );
	}

}